#!/bin/bash

GPIO_CONF="/opt/rk/gpio_conf.txt"
SYSFS_GPIO="/sys/class/gpio"

declare -A SYSFS_GPIO_PIN_ARRAY

function gpio_conf_list_pins()
{
	cat ${GPIO_CONF} | while read READ_LINE; do
		if [[ -z ${READ_LINE} || ${READ_LINE} =~ ^# ]];
		then
			continue
		fi

		echo ${READ_LINE} | awk -F '|' '{print $1}' | awk '{$1=$1; print}'
	done
}

function gpio_conf_get()
{
	if [[ $# -lt 2 ]]; then
		echo -e "[ERROR] ${FUNCNAME} Parameter error." >&2
		return 1
	fi

	local pin=$1
	local opt=$2

	cat ${GPIO_CONF} | while read READ_LINE;
	do
		if [[ -z ${READ_LINE} || ${READ_LINE} =~ ^# ]];
		then
			continue
		fi

		local cur_pin=$(echo ${READ_LINE} | awk -F '|' '{print $1}' | awk '{$1=$1; print}')
		if [[ -n ${cur_pin} && ${cur_pin} == ${pin} ]];
		then
			case ${opt} in
				"PIN")
					echo ${cur_pin}
					;;
				"PORT")
					echo ${READ_LINE} | awk -F '|' '{print $2}' | awk '{$1=$1; print}'
					;;
				"DIR")
					echo ${READ_LINE} | awk -F '|' '{print $3}' | awk '{$1=$1; print}'
					;;
				"LOWACT")
					echo ${READ_LINE} | awk -F '|' '{print $4}' | awk '{$1=$1; print}'
					;;
				"VAL=0")
					echo ${READ_LINE} | awk -F '|' '{print $5}' | awk '{$1=$1; print}'
					;;
				"VAL=1")
					echo ${READ_LINE} | awk -F '|' '{print $6}' | awk '{$1=$1; print}'
					;;
				"DESC")
					echo ${READ_LINE} | awk -F '|' '{print $7}' | awk '{$1=$1; print}'
					;;
			esac

			break
		fi
	done
}

function gpio_pins_export()
{
	while [[ $# -gt 0 ]]; do
		local pin=$1
		local port=$(gpio_conf_get ${pin} PORT)
		local dir=$(gpio_conf_get ${pin} DIR)
		local lowact=$(gpio_conf_get ${pin} LOWACT)

		local sysfs_gpio_pin="${SYSFS_GPIO}/gpio${pin}"
		local sysfs_gpio_port="${SYSFS_GPIO}/${port}"

		if [[ -n ${pin} && ! -d ${sysfs_gpio_pin} ]] \
			&& [[ -n ${port} && ! -d ${sysfs_gpio_port} ]];
		then
			echo ${pin} > ${SYSFS_GPIO}/export
		fi

		if [[ -d ${sysfs_gpio_pin} ]]; then
			SYSFS_GPIO_PIN_ARRAY[${pin}]=${sysfs_gpio_pin}
		elif [[ -d ${sysfs_gpio_port} ]]; then
			SYSFS_GPIO_PIN_ARRAY[${pin}]=${sysfs_gpio_port}
		fi

		if [[ -n ${SYSFS_GPIO_PIN_ARRAY[${pin}]} ]]; then
			local cur_dir=$(cat ${SYSFS_GPIO_PIN_ARRAY[${pin}]}/direction)
			local cur_lowact=$(cat ${SYSFS_GPIO_PIN_ARRAY[${pin}]}/active_low)

			if [[ ${cur_dir} != ${dir} ]]; then
				echo ${dir}    > ${SYSFS_GPIO_PIN_ARRAY[${pin}]}/direction
			fi
			if [[ ${cur_lowact} != ${lowact} ]]; then
				echo ${lowact} > ${SYSFS_GPIO_PIN_ARRAY[${pin}]}/active_low
			fi
		fi

		shift
	done
}

function gpio_pin_set_val()
{
	local pin=$1
	local val=$2

	local dir=$(cat ${SYSFS_GPIO_PIN_ARRAY[${pin}]}/direction)
	if [[ ${dir} != "out" ]]; then
		echo -e "[ERROR] The GPIO is not Output Pin." >&2
		return 1
	fi
	echo ${val} > ${SYSFS_GPIO_PIN_ARRAY[${pin}]}/value
}

function gpio_pin_get_val()
{
	local pin=$1

	cat ${SYSFS_GPIO_PIN_ARRAY[${pin}]}/value
}

function gpio_pin_show()
{
	local pin=$1
	local val=$2
	local port=$(gpio_conf_get ${pin} PORT)
	local dir=$(gpio_conf_get ${pin} DIR)
	local desc=$(gpio_conf_get ${pin} DESC)

	if [[ ${val} == 0 ]]; then
		local val_desc=$(gpio_conf_get ${pin} VAL=0)
	else
		local val_desc=$(gpio_conf_get ${pin} VAL=1)
	fi

	echo -e "SYSFS    : ${SYSFS_GPIO_PIN_ARRAY[${pin}]}"
	echo -e "GPIO Pin : ${pin},${port}"
	echo -e "GPIO Dir : ${dir}"
	echo -e "GPIO Desc: ${desc}"
	echo -e "GPIO Val : ${val},${val_desc}"
}

###############################################

function usage()
{
	echo -e "\nUsage: $0 <cmd> [arg]"
	echo -e "  $(basename $0) help"
	echo -e "  $(basename $0) list"
	echo -e "  $(basename $0) get <pin> ..."
	echo -e "  $(basename $0) set <pin> <val> ..."
}

function line_seperator()
{
	echo -e "-------------------------------------------"
}

if [[ $(id -u) -ne 0 ]]; then
	echo -e "[ERROR] Please run as root!" >&2
	usage
	exit 1
fi

if [[ $# -lt 1 ]]; then
	echo -e "[ERROR] Parameter error!" >&2
	usage
	exit 1
fi

if [[ ! -r ${GPIO_CONF} ]]; then
	echo -e "[ERROR] Board GPIO Conf file cannot be read: ${GPIO_CONF}!" >&2
	exit 1
fi


CMD=$1
shift
case ${CMD} in
	"help" )
		usage
		;;
	"list" )
		echo -e "[INFO] List all GPIOs in Config File\n"
		printf "%-5s%-9s%-8s%-20s\n" "Pin" "Port" "Dir" "Description"
		line_seperator

		for PIN in $(gpio_conf_list_pins); do
			PORT=$(gpio_conf_get ${PIN} PORT)
			DIR=$(gpio_conf_get ${PIN} DIR)
			DESC=$(gpio_conf_get ${PIN} DESC)
			printf "%-5s%-9s%-8s%-20s\n" "${PIN}" "${PORT}" "${DIR}" "${DESC}"
		done
		;;
	"get" )
		while [[ $# -ge 1 ]]; do
			PIN=$(gpio_conf_get $1 PIN)
			line_seperator

			if [[ -z ${PIN} ]]; then
				echo -e "[ERROR] GPIO Pin $1 not supported.\n" >&2
			else
				gpio_pins_export ${PIN}

				VAL=$(gpio_pin_get_val ${PIN})
				echo -e "[INFO] GPIO Pin ${PIN} Get OK.\n"
				gpio_pin_show ${PIN} ${VAL}
			fi

			shift
		done
		;;
	"set")
		while [[ $# -ge 2 ]]; do
			PIN=$(gpio_conf_get $1 PIN)
			DIR=$(gpio_conf_get $1 DIR)
			VAL=$2
			line_seperator

			if [[ -z ${PIN} || -z ${DIR} ]]; then
				echo -e "[ERROR] GPIO Pin $1 not supported.\n" >&2
			elif [[ ${DIR} != "out" ]]; then
				echo -e "[ERROR] GPIO Pin $1 is not an OUT Pin.\n" >&2
			else
				gpio_pins_export ${PIN}

				gpio_pin_set_val ${PIN} ${VAL}
				echo -e "[INFO] GPIO Pin ${PIN} Set OK.\n"
				VAL=$(gpio_pin_get_val ${PIN})
				gpio_pin_show ${PIN} ${VAL}
			fi

			shift 2
		done
		;;
	*)
		echo -e "[ERROR] Unsupport command!\n" >&2
		exit 1
		;;
esac
